package ru.urfc.portal.ui.client.descriptor;

import java.util.Date;

import ru.urfc.portal.ui.client.Utils;

import com.extjs.gxt.ui.client.data.DataField;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelType;

public class SimpleGridField extends GridField {
	private String fieldMap;
	private Class<?> fieldClass;
	private String format;

	public SimpleGridField(String fieldMap, Class<?> fieldClass) {
		this(fieldMap, fieldClass, null);
	}

	public SimpleGridField(String fieldMap, Class<?> fieldClass, String format) {
		this.fieldMap = fieldMap;
		this.fieldClass = fieldClass;
		this.format = format;
	}

	@Override
	public GridField init(String fieldName, GridDescriptor gridDescriptor, ModelType modelType) {
		DataField dataField = new DataField(fieldName, fieldMap);
		if (isBoolean()) {
			dataField.setType(null);
		} else if (isDateWithDefaultFormat()) {
			dataField.setType(null);
		} else {
			dataField.setType(fieldClass);
		}
		dataField.setFormat(format);
		modelType.addField(dataField);
		return super.init(fieldName, gridDescriptor, modelType);
	}

	private boolean isBoolean() {
		return Boolean.class.equals(fieldClass);
	}

	private boolean isDateWithDefaultFormat() {
		return Date.class.equals(fieldClass) && format == null;
	}

	static class DateParser {
		protected String format;
		protected String matchPattern;
		protected int maxLength;

		public DateParser(String format) {
			this.format = format;
			this.matchPattern = defaultPattern(format);
			this.maxLength = format.replace("'", "").length();
		}

		private static String defaultPattern(String format) {
			return format.replaceAll("[yMdHmsS]", "\\\\d").replaceAll("'T'", "T") + ".*";
		}
		
		boolean match(String date) {
			return date.matches(matchPattern);
		}

		public Date parse(String str) {
			return Utils.parseDate(format, str.substring(0, maxLength));
		}
		
	}
		
	private DateParser[] defaultDateParsers = {
		new DateParser("yyyy-MM-dd'T'HH:mm:ss.SSS"),
		new DateParser("yyyy-MM-dd'T'HH:mm:ss"),
		new DateParser("yyyy-MM-dd")
	};
		
	@Override
	protected Object _getValue(ModelData modelData) {
		Object result = modelData.get(getName());
		if (result != null && fieldClass != null && result instanceof String) {
			String str = (String) result;
			if (isBoolean()) {
				str = str.toLowerCase();
				if (!str.matches("(true)|(false)")) {
					throw new ClassCastException("Can't cast '" + result + "' to true or false");
				}
				return updateModel(modelData, Boolean.valueOf(str));
			} if (isDateWithDefaultFormat()) {
				for (DateParser parser: defaultDateParsers) {
					if (parser.match(str)) {
						return updateModel(modelData, parser.parse(str));
					}
				}
			}
		}
		return result;
	}
	
	public String getSerializedValue(ModelData modelData) {
		Object value = _getValue(modelData);
		if (value == null) {
			 return null;
		}
		if (value instanceof Date) {
			String dateFormat = (format == null) ? Utils.SERIALIZE_DATE_FORMAT : format;
			String result = Utils.formatDate(dateFormat, (Date) value);
			if (dateFormat.endsWith("Z")) {
				result = result.replaceAll("(..)$", ":" + result.substring(result.length() - 2));
			}
			return result;
		}
		return value.toString();
	}
	
	private Object updateModel(ModelData modelData, Object value) {
		modelData.set(getName(), value);
		return value;
	}

	public String getFieldMap() {
		return fieldMap;
	}
	
	public String getFormat() {
		return format;
	}
	
	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
	
}
